(function(angular) {
  'use strict';
  angular
    .module('fs.ajax', ['ngResource', 'fs.logger', 'fs.storage'])
    .config([
      '$resourceProvider',
      function($resourceProvider) {
        $resourceProvider.stripTrailingSlashes = false;
      }
    ])
    .provider('ajaxServiceFactory', function() {
      var provider = this;
      provider.baseUrl = '';
      provider.params = {};
      provider.setBaseUrl = function(url) {
        provider.baseUrl = url;
      };
      provider.setDefaultParmas = function(params) {
        provider.params = params;
      };
      provider.$get = [
        '$resource',
        '$q',
        '$timeout',
        'loggerFactory',
        'storageService',
        '$parse',
        function($resource, $q, $timeout, loggerFactory, storageService, $parse) {
          var log = loggerFactory.getLogger('ajaxServiceFactory');
          return {
            buildAjaxService: buildAjaxService,
            setBaseUrl: provider.setBaseUrl,
            setDefaultParmas: provider.setDefaultParmas
          };

          function buildAjaxService(configs) {
            var services = {},
              serviceConfig;
            angular.forEach(configs, function(config, key) {
              if (config.url) {
                config.url = config.url;
              }
              if (provider.baseUrl && config.url) {
                config.url = provider.baseUrl + config.url;
              }
            });
            services = $resource(provider.baseUrl, provider.params, configs);
            return createProxyService(configs, services);
          }
          function handleKeepPageNoProperty(searchCriteria) {
            if (!searchCriteria.keepPageNo) {
              searchCriteria.pageNo = 1;
              delete searchCriteria.keepPageNo;
            }
          }
          function createProxyService(configs, services) {
            var proxyService = {};
            angular.forEach(configs, function(config, key) {
              proxyService[key] = function(params) {
                var deferred = $q.defer(),
                  hasStorageSearchCriteria = false;
                if (params) {
                  for (var prop in params) {
                    if (params[prop] && params[prop].pageNo && params[prop].pageSize) {
                      handleKeepPageNoProperty(params[prop]);
                      break;
                    }
                  }
                  if (params.searchCriteria && params.searchCriteria.$type == 'SearchCriteria' && params.searchCriteria.storageSearchCriteria == true) {
                    storageService.saveSearchCriteria(params.searchCriteria);
                    hasStorageSearchCriteria = true;
                  }
                  if (!hasStorageSearchCriteria && angular.isObject(params)) {
                    for (var prop in params) {
                      if (params[prop] && params[prop].$type == 'SearchCriteria') {
                        if (params[prop].storageSearchCriteria == true) {
                          storageService.saveSearchCriteria(params[prop]);
                        }
                        break;
                      }
                    }
                  }
                }
                return sendRequest(config, services[key], params);
              };
            });
            return proxyService;
          }

          function sendRequest(config, service, params) {
            var deferred = $q.defer(),
              hasSetSearchCriteriaInfo = false;
            try {
              params = angular.copy(params);
            } catch (e) {
              log.debug('can not copy the params:' + params);
              deferred.reject(e);
            }
            service(
              params,
              function(response) {
                if (params && response) {
                  if (params.searchCriteria && params.searchCriteria.$type == 'SearchCriteria' && params.searchCriteria.storageSearchCriteria == true) {
                    $parse('searchCriteria.$type').assign(response.data, params.searchCriteria.$type);
                    $parse('searchCriteria.$state').assign(response.data, params.searchCriteria.$state);
                    $parse('searchCriteria.storageSearchCriteria').assign(response.data, params.searchCriteria.storageSearchCriteria);
                    hasSetSearchCriteriaInfo = true;
                  }
                  if (!hasSetSearchCriteriaInfo && angular.isObject(params)) {
                    for (var prop in params) {
                      if (params[prop] && params[prop].$type == 'SearchCriteria') {
                        if (params[prop].storageSearchCriteria == true) {
                          $parse(prop + '.$type').assign(response.data, params[prop].$type);
                          $parse(prop + '.$state').assign(response.data, params[prop].$state);
                          $parse(prop + '.storageSearchCriteria').assign(response.data, params[prop].storageSearchCriteria);
                        }
                        break;
                      }
                    }
                  }
                }
                deferred.resolve({
                  data: response ? response.data : response
                });
              },
              function(error) {
                deferred.reject(error);
              }
            );
            return deferred.promise;
          }
        }
      ];
    });
})(angular);
